//
// Copyright 2001-2004 Stottler Henke Associates, Inc.
// All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////

package com.stottlerhenke.simbionic.engine.core;

import java.util.*;
import com.stottlerhenke.simbionic.common.*;
import com.stottlerhenke.simbionic.engine.file.SB_StreamReader;
import com.stottlerhenke.simbionic.engine.parser.*;
import com.stottlerhenke.simbionic.api.*;
import com.stottlerhenke.simbionic.engine.*;


/**
 * An instance of this class contains a list of parameters for a behavior,
 * action, or predicate.
 */
public class SB_ParamList  
{
  protected ArrayList _params;
  public SB_ParamList() {
    _params = new ArrayList();
  }

  public void add(SB_Parameter param)
  {
    _params.add(param);
  }

  public int GetNumParams() { return _params.size(); }

  public SB_Parameter GetParam(int index) { return (SB_Parameter) _params.get(index); }

	/**
	 * Loads a list of parameters from a stream.
	 * @param reader the stream reader to load from
	 */
  public void load(SB_StreamReader reader,SB_SingletonBook book) throws SB_FileException
	{
    // read num of params
    int numParams = reader.readInt();

    if(SIM_Constants.DEBUG_INFO_ON)
      book.getLogger().log(".Loading " + numParams + " parameters...",SB_Logger.INIT);

    for (int i = 0; i < numParams; i++)
    {
      // read param
      SB_Parameter param = new SB_Parameter();
      param.load(reader,book);

	    if(SIM_Constants.DEBUG_INFO_ON)
	    	book.getLogger().log(".\tLoaded " + param,SB_Logger.INIT);

	    _params.add(param);
    }
  }

  public void Instantiate(SB_VariableMap vars){
    for (int i = 0; i < _params.size(); i++){
      SB_Parameter parmIt = (SB_Parameter) _params.get(i);
      try{
        vars.AddVariable(parmIt.GetName(),
                         SB_Variable.newVariable(parmIt.GetType().getState()));
      }catch(SB_Exception e){

      }
    }
  }


  /**
   * TODO We need to compare the given args with the expected parameter
   * types to determine if the args are valid.
   * 
   * @param frame
   * @param args
   */
  public void UnpackArgs(SB_ExecutionFrame frame, ArrayList args){
    SB_Variable argIt;
    for (int j = 0; j < _params.size(); j++) {
      argIt = (SB_Variable) args.get(j);
      frame.SetVariable( ((SB_Parameter) _params.get(j)).GetName(), argIt);

      if(SIM_Constants.DEBUG_INFO_ON)
        frame.GetLogger().log("[ID*,STK " + frame.GetStackDepth() + "] BINDING:\tsyncing behavior param "
        					+ ((SB_Parameter) _params.get(j)).toString() + " = " + argIt.toString(),SB_Logger.BINDING);
    }
  }

  public void UnpackArgs(SB_ExecutionFrame frame, ArrayList retVals, ArrayList args)
  throws SB_Exception
  {
    SB_Param retValIt;
    SB_Expression actualParamIt;
    SB_Parameter parmIt;

    for (int i = 0; i < _params.size(); i++) {
      retValIt = (SB_Param)retVals.get(i);
      actualParamIt = (SB_Expression)args.get(i);
      parmIt = (SB_Parameter) _params.get(i);
      // only unpack in/out or out parameters
      if (parmIt.IsOut()) {
        // only bind the predicate's "out" params to args if the arg is a valid LHS value
        if ( (actualParamIt).GetType() == EExpressionType.kVariable) {
          //SB_Variable retVal = SB_SimInterface.ConvertParamAuto(retValIt, frame.GetBook());
          SB_VarData retVal = new SB_VarData(retValIt.getData());
          
          // sync up the return value with the actual variable parameter
          SB_ExpVariable actualParam = (SB_ExpVariable)(actualParamIt);
          frame.SetVariable(actualParam.GetName(), retVal);

				  if(SIM_Constants.DEBUG_INFO_ON)
						frame.GetLogger().log("[ID*,STK " + frame.GetStackDepth() + "] BINDING:\tsyncing predicate param "
										+ parmIt.toString() + ": " + actualParam.GetName() + " = " + retVal.toString(),SB_Logger.BINDING);
        }
      }
    }
   // }
  }

  public SB_Parameter GetParam( String name){
    SB_Parameter parmIt;
    for (int i = 0; i <_params.size(); i++)
    {
      parmIt = (SB_Parameter)_params.get(i);
      if (parmIt.GetName().compareTo(name) == 0)
      return parmIt;
     }
     return null;
  }


  public String toString (){
    String out;
    out = new String( "ParamList (" + Integer.toString(_params.size()) +  " params)" );
    for(int i = 0; i < _params.size(); i++){
      out = out + "/t" + ((SB_Parameter)_params.get(i)).toString();
    }
    return out;
  }

}